#include "CBondInfoImpl.h"

template <>
inline int GetTypeEncoding<CBondInfoImpl::FieldFlag>() {
  return (kFieldDataTypeChar << 16) + sizeof(CBondInfoImpl::FieldFlag);
}

#define RTL_FIELD_SIZE(type, field) (sizeof(((type*)0)->field))
#define FIELD_OFFSET(type, field) offsetof(type, field)
#define CASE_SYNC(FIELD)                   \
  case FIELD_OFFSET(CBondInfoImpl, FIELD): \
    if (write) {                           \
      FIELD.Write(input, len);             \
    } else {                               \
      return FIELD.Read();                 \
    };                                     \
    break;
#define CASE_SYNC_TYPE(FIELD, TYPE)        \
  case FIELD_OFFSET(CBondInfoImpl, FIELD): \
    if (write) {                           \
      FIELD = *((TYPE*)input);             \
    } else {                               \
      return (const char*)(&FIELD);        \
    };                                     \
    break;

#define CASE_INFO(FIELD)                           \
  case FIELD_OFFSET(CBondInfoImpl, FIELD):         \
    if (mode == FieldModeBytes) {                  \
      return FIELD.GetDirectMemSize();             \
    }                                              \
    if (mode == FieldModeSharedBytes) {            \
      return FIELD.GetSharedMemSize();             \
    }                                              \
    if (mode == FieldModeCategory) {               \
      return FIELD.Category();                     \
    }                                              \
    if (mode == FieldModeType) {                   \
      return FIELD.TypeEncoding();                 \
    }                                              \
    if (mode == FieldModeName) {                   \
      memcpy(name, #FIELD, strlen(#FIELD));        \
      return RTL_FIELD_SIZE(CBondInfoImpl, FIELD); \
    }                                              \
    break;

#define CASE_INFO_TYPE(FIELD, TYPE)                \
  case FIELD_OFFSET(CBondInfoImpl, FIELD):         \
    if (mode == FieldModeBytes) {                  \
      return sizeof(TYPE);                         \
    }                                              \
    if (mode == FieldModeCategory) {               \
      return 0;                                    \
    }                                              \
    if (mode == FieldModeType) {                   \
      return GetTypeEncoding<TYPE>();              \
    }                                              \
    if (mode == FieldModeName) {                   \
      memcpy(name, #FIELD, strlen(#FIELD));        \
      return RTL_FIELD_SIZE(CBondInfoImpl, FIELD); \
    }                                              \
    break;

int CBondInfoImpl::GetMemoryBytes(int& validbytes) const {
  validbytes = sizeof(CBondInfoImpl);
  return validbytes;
}
int CBondInfoImpl::GetAllFields(std::vector<FieldInfo>& fields) const {
  char buf[1024] = {0};
  for (int i = 0; i < sizeof(CBondInfoImpl);) {
    memset(buf, 0, 1024);
    int size = GetFieldInfo(i, buf, FieldModeName);
    if (size > 0) {
      FieldInfo fi;
      fi.index = fields.size();
      fi.offset = i;
      fi.size = size;
      fi.name = buf;
      if (fields.size() > 0) {
        FieldInfo& last = fields[fields.size() - 1];
        last.gap = fi.offset - (last.offset + last.size);
      }
      fields.push_back(fi);
      i += fi.size;
    } else
      i++;
  }
  if (fields.size() > 0) {
    FieldInfo& last = fields[fields.size() - 1];
    last.gap = sizeof(CBondInfoImpl) - (last.offset + last.size);
  }
  return fields.size();
}
int CBondInfoImpl::GetFieldInfo(int offset, char* name,
                                FieldAccessMode mode) const {
  switch (offset) {
    // CASE_INFO(m_sJianpin);
    // CASE_INFO(m_sQuanpin);
    CASE_INFO(m_ConversionRate);
    CASE_INFO(m_sBidLimitBottom);
    CASE_INFO(m_sBidLimitTop);
    CASE_INFO(m_IssueRate);
    CASE_INFO(m_sCouponRateCurrent);
    CASE_INFO(m_sFullName);
    CASE_INFO(m_sFullNameEn);
    CASE_INFO(m_sShortName);
    CASE_INFO(m_sShortNameEn);
    CASE_INFO(m_sCombBondKey);
    CASE_INFO(m_sBondKey);
    CASE_INFO(m_sCombBondID);
    CASE_INFO(m_sRemainDate);
    CASE_INFO(m_sRemainDateDisplay);
    CASE_INFO(m_sTermToMaturity);
    CASE_INFO(m_sIssueEndTime);
    CASE_INFO(m_sAuctionDateTime);
    CASE_INFO(m_NextCoupon_Date);
    CASE_INFO(m_PlannedExerciseDate);
    CASE_INFO(m_sAuctionDateEnd);
    CASE_INFO(m_sOptionDate);
    CASE_INFO(m_sAuctionDateStart);
    CASE_INFO(m_sIssueEndDate);
    CASE_INFO(m_sPaymentDate);
    CASE_INFO(m_sAnnounceDate);
    CASE_INFO(m_sIssueStartDate);
    CASE_INFO(m_sInterestStartDate);
    CASE_INFO(m_sListDate);
    CASE_INFO(m_sMaturityDate);
    CASE_INFO(m_sYieldCurveType);
    CASE_INFO(m_sJointUnderwriters);
    CASE_INFO(m_sUnderwrites);
    CASE_INFO(m_sIssuerRatingInstitutionCode);
    CASE_INFO(m_sAuction_Unit);
    CASE_INFO(m_sIssueType);
    CASE_INFO(m_sOutlook);
    CASE_INFO_TYPE(m_sListedMarket, qb::base::KeyString);
    CASE_INFO(m_sOptionType);
    CASE_INFO(m_sAutcionType);
    CASE_INFO(m_sEntCor);
    CASE_INFO(m_sInstitutionType);
    CASE_INFO(m_sMarketType);
    CASE_INFO(m_sBondSubType);
    CASE_INFO(m_sInterestBasis);
    CASE_INFO(m_sCouponFrequency);
    CASE_INFO(m_sCompoundFrequency);
    CASE_INFO(m_sWarrant);
    CASE_INFO(m_sMainUnderwriters);
    CASE_INFO(m_sIssuePeriod);
    CASE_INFO(m_sAuction_Step);
    CASE_INFO(m_sFRNIndexID);
    CASE_INFO(m_sIssuerRating);
    CASE_INFO(m_sBondRating);
    CASE_INFO(m_sInstitutionRating);
    CASE_INFO(m_sRateType);
    CASE_INFO(m_sCouponType);
    CASE_INFO(m_sMaturityTerm);
    CASE_INFO(m_sBondID);
    // CASE_INFO(m_sCSCleanPrice);
    // CASE_INFO(m_sCSYield);
    CASE_INFO(m_sAuction_Cap);
    CASE_INFO(m_sAuction_Flr);
    CASE_INFO(m_sFixingMADays);
    // CASE_INFO(m_sCSModifyDuration);
    CASE_INFO(m_sIssuerCode);
    CASE_INFO_TYPE(m_sAssetStatus, qb::base::KeyString);
    CASE_INFO_TYPE(m_sPrincipayPayType, qb::base::KeyString);
    CASE_INFO_TYPE(m_fPlannedIssueAmount, double);
    CASE_INFO_TYPE(m_fActualIssueAmount, double);
    CASE_INFO_TYPE(m_fOutstandingAmount, double);
    CASE_INFO_TYPE(m_nBondFileNum, int);
    CASE_INFO_TYPE(m_nAdditionInfoIndex, int);
    CASE_INFO_TYPE(m_nOptionInfoIndex, int);
    // CASE_INFO_TYPE(m_nCSDate, UINT);
    CASE_INFO_TYPE(m_nAuctionTimeStart, int);
    CASE_INFO_TYPE(m_nAuctionTimeEnd, int);
    CASE_INFO_TYPE(m_nCdcAuth, int);
    CASE_INFO_TYPE(m_flag, unsigned short);
    default:
      break;
  }
  return 0;
}
void CBondInfoImpl::WriteField(int offset, const char* str, int len) {
  SyncField(offset, str, len, true);
}

int CBondInfoImpl::ReadField(int offset, void* buf, int capcity,
                             int& type) const {
  // 要求buf足够大,此处对buf不做检查
  // 读取到的数据是原始CBondContainer也能读取到的数据
  CBondInfoImpl* object = const_cast<CBondInfoImpl*>(this);
  const char* data = object->SyncField(offset, 0, 0, false);
  type = GetFieldType(offset);
  kFieldDataType datatype = (kFieldDataType)(type >> 16);
  int arrayLength = type & 0x0000ffff;

  // GetStorageBytes返回的是字符串所占内存加额外指针等内存
  // 对于非kFieldDataTypeChar,kFieldDataTypeString类型,都为原始字段
  // 原始字段的大小可以通过GetStorageBytes来获取
  int size = 0;
  if (datatype == kFieldDataTypeString) {
    size = strlen(data);
  } else if (datatype == kFieldDataTypeChar && arrayLength > 0) {
    size = strlen(data);
  } else {
    switch (datatype) {
      case kFieldDataTypeBool:
        size = 1;
        break;
      case kFieldDataTypeChar:
        size = sizeof(char);
        break;
      case kFieldDataTypeShort:
        size = sizeof(short);
        break;
      case kFieldDataTypeUShort:
        size = sizeof(short);
        break;
      case kFieldDataTypeInt:
        size = sizeof(int);
        break;
      case kFieldDataTypeUINT:
        size = sizeof(UINT);
        break;
      case kFieldDataTypeFloat:
        size = sizeof(float);
        break;
      case kFieldDataTypeDouble:
        size = sizeof(double);
        break;
      default:
        break;
    }
  }
  if (size > 0) memcpy(buf, data, size);
  ((char*)buf)[size] = 0;
  return size;
}
int CBondInfoImpl::GetFieldByOffset(int offset, void* buf, int capcity,
                                    int& type) const {
  return ReadField(offset, buf, capcity, type);
}
int CBondInfoImpl::GetStorageBytes(int offset) const {
  // 获取指定列的存储对象的内存总和(不是一个,是所有之和)
  return GetFieldInfo(offset, 0, FieldModeBytes);
}
int CBondInfoImpl::GetFieldCategory(int offset) const {
  return GetFieldInfo(offset, 0, FieldModeCategory);
}
int CBondInfoImpl::GetFieldType(int offset) const {
  return GetFieldInfo(offset, 0, FieldModeType);
}
const char* CBondInfoImpl::SyncField(int offset, const char* input, int len,
                                     bool write) {
  switch (offset) {
    // CASE_SYNC(m_sJianpin);
    // CASE_SYNC(m_sQuanpin);
    CASE_SYNC(m_ConversionRate);
    CASE_SYNC(m_sBidLimitBottom);
    CASE_SYNC(m_sBidLimitTop);
    CASE_SYNC(m_IssueRate);
    CASE_SYNC(m_sCouponRateCurrent);
    CASE_SYNC(m_sFullName);
    CASE_SYNC(m_sFullNameEn);
    CASE_SYNC(m_sShortName);
    CASE_SYNC(m_sShortNameEn);
    CASE_SYNC(m_sCombBondKey);
    CASE_SYNC(m_sBondKey);
    CASE_SYNC(m_sCombBondID);
    CASE_SYNC(m_sRemainDate);
    CASE_SYNC(m_sRemainDateDisplay);
    CASE_SYNC(m_sTermToMaturity);
    CASE_SYNC(m_sIssueEndTime);
    CASE_SYNC(m_sAuctionDateTime);
    CASE_SYNC(m_NextCoupon_Date);
    CASE_SYNC(m_PlannedExerciseDate);
    CASE_SYNC(m_sAuctionDateEnd);
    CASE_SYNC(m_sOptionDate);
    CASE_SYNC(m_sAuctionDateStart);
    CASE_SYNC(m_sIssueEndDate);
    CASE_SYNC(m_sPaymentDate);
    CASE_SYNC(m_sAnnounceDate);
    CASE_SYNC(m_sIssueStartDate);
    CASE_SYNC(m_sInterestStartDate);
    CASE_SYNC(m_sListDate);
    CASE_SYNC(m_sMaturityDate);
    CASE_SYNC(m_sYieldCurveType);
    CASE_SYNC(m_sJointUnderwriters);
    CASE_SYNC(m_sUnderwrites);
    CASE_SYNC(m_sIssuerRatingInstitutionCode);
    CASE_SYNC(m_sAuction_Unit);
    CASE_SYNC(m_sIssueType);
    CASE_SYNC(m_sOutlook);
    CASE_SYNC_TYPE(m_sListedMarket, qb::base::KeyString);
    CASE_SYNC(m_sOptionType);
    CASE_SYNC(m_sAutcionType);
    CASE_SYNC(m_sEntCor);
    CASE_SYNC(m_sInstitutionType);
    CASE_SYNC(m_sMarketType);
    CASE_SYNC(m_sBondSubType);
    CASE_SYNC(m_sInterestBasis);
    CASE_SYNC(m_sCouponFrequency);
    CASE_SYNC(m_sCompoundFrequency);
    CASE_SYNC(m_sWarrant);
    CASE_SYNC(m_sMainUnderwriters);
    CASE_SYNC(m_sIssuePeriod);
    CASE_SYNC(m_sAuction_Step);
    CASE_SYNC(m_sFRNIndexID);
    CASE_SYNC(m_sIssuerRating);
    CASE_SYNC(m_sBondRating);
    CASE_SYNC(m_sInstitutionRating);
    CASE_SYNC(m_sRateType);
    CASE_SYNC(m_sCouponType);
    CASE_SYNC(m_sMaturityTerm);
    CASE_SYNC(m_sBondID);
    // CASE_SYNC(m_sCSCleanPrice);
    // CASE_SYNC(m_sCSYield);
    CASE_SYNC(m_sAuction_Cap);
    CASE_SYNC(m_sAuction_Flr);
    CASE_SYNC(m_sFixingMADays);
    // CASE_SYNC(m_sCSModifyDuration);
    CASE_SYNC(m_sIssuerCode);
    CASE_SYNC_TYPE(m_sAssetStatus, qb::base::KeyString);
    CASE_SYNC_TYPE(m_sPrincipayPayType, qb::base::KeyString);
    CASE_SYNC_TYPE(m_fPlannedIssueAmount, double);
    CASE_SYNC_TYPE(m_fActualIssueAmount, double);
    CASE_SYNC_TYPE(m_fOutstandingAmount, double);
    CASE_SYNC_TYPE(m_nBondFileNum, int);
    CASE_SYNC_TYPE(m_nAdditionInfoIndex, int);
    CASE_SYNC_TYPE(m_nOptionInfoIndex, int);
    // CASE_SYNC_TYPE(m_nCSDate, UINT);
    CASE_SYNC_TYPE(m_nAuctionTimeStart, int);
    CASE_SYNC_TYPE(m_nAuctionTimeEnd, int);
    CASE_SYNC_TYPE(m_nCdcAuth, int);
    CASE_SYNC_TYPE(m_flag, unsigned short);
    default:
      break;
  }
  return 0;
}
void CBondInfoImpl::ChangeFieldMode(bool getName) {}
void CBondInfoImpl::RecordRepeatCheck() {
  // 	static DWORD lastreport = 0;
  // 	struct FieldMemoryInfo{
  // 		int			pod_memory;			//
  // 直接内存大小 		int			shared_key;
  // //共享的key 		FieldMemoryInfo() :pod_memory(0), shared_key(0){}
  // 	};
  // 	if (GetTickCount() > lastreport + 20000)
  // 		lastreport = GetTickCount();
  // 	else
  // 		return;
  // 	CBondInfoImpl bond;
  // 	vector<FieldInfo> fields;
  // 	vector<FieldMemoryInfo> meminfos;
  // 	bond.GetAllFields(fields);
  //
  // 	int total = 0;
  // 	meminfos.reserve(fields.size());
  // 	for (int i = 0; i < (int)fields.size(); i++)
  // 		meminfos.push_back(FieldMemoryInfo());
  //
  // 	// 统计每一列的直接内存有多少
  // 	qb::base::HighResTime timer;
  // 	AfxGetBondContainer().Lock();
  // 	int nsize = AfxGetBondContainer().GetSize();
  // 	for (int i = 0; i < nsize; i++)
  // 	{
  // 		const CBondInfo& bi = AfxGetBondContainer().ElementAtR(i);
  // 		for (int j = 0; j < (int)fields.size(); j++)
  // 		{
  // 			FieldInfo& fi = fields[j];
  // 			int bytes = bi.GetStorageBytes(fi.offset);
  // 			meminfos[j].pod_memory += bi.GetStorageBytes(fi.offset);
  // 			total += bytes;
  // 		}
  // 	}
  // 	AfxGetBondContainer().UnLock();
  // 	qb::base::HighResTime readlast = timer.elapsed();
  // 	// 统计每一列的共享内存总共有多少
  // 	map<int,int> visited;
  // 	for (int i = 0; i < (int)fields.size(); i++)
  // 	{
  // 		int offset = fields[i].offset;
  // 		int category = bond.GetFieldCategory(offset);
  // 		if (category==0)
  // 			continue;
  // 		meminfos[i].shared_key = category;
  // 		if (visited.find(category) != visited.end())
  // 			continue;
  // 		int bytes = bond.GetFieldInfo(offset, 0, FieldModeSharedBytes);
  // 		visited[category] = bytes;
  // 		total += bytes;
  // 	}
  //
  // 	BVIEW("[NEWBONDS] 所有的CBondInfoImpl的内存统计输出如下:");
  // 	BVIEW("[NEWBONDS] 总共内存:%10d  债券个数:%6d  CBondInfoOld:%d
  // CBondInfoImpl:%d  直接总内存:%d  全部读取耗时:%dus", total, nsize,
  // 		sizeof(CBondInfoOld), sizeof(CBondInfoImpl),
  // sizeof(CBondInfoImpl)*nsize, readlast.microsec()); 	BVIEW("[NEWBONDS]
  // 直接内存是每个字段直接拥有的内存总和,共享内存是所有该字段共享的内存总和");
  // 	BVIEW("[NEWBONDS]
  // 共享key相同对应的共享内存实质上是同一份内存,如所有的日期字段");
  // 	BVIEW("[NEWBONDS] %32s  ,%10s  ,%10s  ,%4s", "列", "直接内存",
  // "共享内存", "共享key"); 	struct MemInfo{ 		string	name; 		int
  // bytes; 		int		share; 		int		key; 	public: 		bool
  // operator<(const MemInfo& mi)const{return bytes > mi.bytes;}
  // 	};
  //
  // 	static BondChecker checker;
  // 	vector<MemInfo> infos; infos.reserve(fields.size());
  // 	for (int i = 0; i < (int)fields.size(); i++)
  // 	{
  // 		MemInfo mi; mi.name = fields[i].name;
  // 		mi.bytes = meminfos[i].pod_memory;
  // 		mi.share = visited[meminfos[i].shared_key];
  // 		mi.key = meminfos[i].shared_key;
  // 		infos.push_back(mi);
  // 	}
  // 	std::sort(infos.begin(), infos.end());
  // 	for (int i = 0; i < (int)fields.size(); i++)
  // 	{
  // 		BVIEW("[NEWBONDS] %32s  ,%10d  ,%10d  ,%4d",
  // 			infos[i].name.c_str(), infos[i].bytes,
  // 			infos[i].share, infos[i].key
  // 			);
  // 	}
  //
}
// void CBondInfoImpl::CheckEqual(CBondInfoImpl* impl, CBondInfoOld* old)
// {
// 	static BondChecker checker;
// 	checker.CheckEqual(*impl, *old);
// }
